package com.jy.api.service.impl;

import com.jy.api.dao.*;
import com.jy.api.domain.*;
import com.jy.api.service.EmployeeService;
import com.jy.api.service.ProductService;
import com.jy.api.service.StoreService;
import com.jy.api.signUpReq.MarsCallReq.MarsCallRes;
import com.jy.api.signUpReq.MarsCallReq.SetStoreCallTime;
import com.jy.api.signUpReq.MarsCallReq.UpdateRewardReq;
import com.jy.api.signUpReq.MarsCallReq.UpdateStoreReq;
import com.jy.api.signUpReq.ProductDatRes;
import com.jy.api.signUpReq.admin.SetPswReq;
import com.jy.api.signUpReq.admin.StoreReq;
import com.jy.api.signUpReq.admin.StoreSignUpReq;
import com.jy.api.signUpReq.admin.StoreUpdateReq;
import com.jy.api.util.Result;
import com.jy.api.util.*;
import com.jy.api.vo.admin.store.StoreVo;
import com.jy.api.vo.member.StoreMemberInfoVo;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

@Slf4j
@Service
public class StoreServiceImpl implements StoreService {

    @Autowired
    StoreDao storeDao;

    @Autowired
    StoreProfileDao storeProfileDao;

    @Autowired
    EmployeeService employeeService;

    @Autowired
    SalesUrlUtil salesUrlUtil;
    @Autowired
    private EmployeeDao employeeDao;


    @Autowired
    RestTemplate restTemplate;

    @Autowired
    MemberAccountDao memberAccountDao;
    @Autowired
    private ProductService productService;
    @Autowired
    private StoreTypeDao storeTypeDao;
    @Autowired
    private ProductTypeDayCountDao countDao;
    @Autowired
    private ProductTypeDao productTypeDao;
    @Autowired
    private RewardDao rewardDao;
    @Autowired
    private StorePayDao storePayDao;
    @Autowired
    private CallServiceDao callServiceDao;

    @Override
    public List<StoreVo> getStores(String userName, boolean status) throws ParseException {
        List<StoreVo> storeVos = new ArrayList<>();
        List<String> storeIds = null;
        if (status) {
            storeIds = employeeService.getStoreIds(userName);
        } else {
            storeIds = employeeService.getStoresPartner(userName);
        }
        List<Map<String, Object>> stores = storeDao.getStoreList(userName, storeIds);
        for (Map<String, Object> map : stores) {
            StoreVo storeVo = new StoreVo(map.get("id").toString(), map.get("name").toString(),
                    map.get("addr").toString(), map.get("referralCode").toString(),
                    map.get("addTime") != null ? MyDateUtils.stringToDate(map.get("addTime").toString()) : new Date(),
                    map.get("updateTime") != null ? MyDateUtils.stringToDate(map.get("updateTime").toString()) : new Date(),
                    map.get("typeCode").toString(), Boolean.valueOf(map.get("call").toString()));
            storeVo.setMakeEnabled(Boolean.parseBoolean(map.get("makeEnabled") == null ? "false" : map.get("makeEnabled").toString()));
            storeVo.setMakeEndTime(map.get("makeEndTime") != null ? MyDateUtils.stringToDate(map.get("makeEndTime").toString()) : null);
            storeVos.add(storeVo);
        }
        return storeVos;
    }

    @Override
    @Transactional
    public Store addStore(String storeId, StoreSignUpReq storeOrder,
                          String username, StoreType storeType) throws IOException {
        Store store = storeDao.findOne(storeId);
        if (store == null) {
            store = new Store();
            BeanUtils.copyProperties(storeOrder, store);
            store.setId(storeId);
            store.setUsername(username);
            employeeService.addEmployee(store, username);
        } else {
            store.setName(storeOrder.getName());
            store.setAddr(storeOrder.getAddr());
        }
        if (!StringUtils.equals(store.getTypeCode(),
                storeType.getCode())) {
            store.setTypeCode(storeType.getCode());
            store.setTypeName(storeType.getName());
        }

        reduceCode(storeOrder.getReferralCode());
        //默认过期时间为 修改推荐码后1个月
        store.setExpireTime(MyDateUtils.increaseMonth(new Date(), 1));
        //这里直接生成storeId.zip
        //store.setClientUrl(getNewUrl(storeId));
        store.setCallSecond(30);
        storeDao.save(store);

        productService.createProductData(storeId);
        return store;
    }

    private void putCode(Map<String, String> map) {
        String msg = null;
        try {
            //同步验证码
            String url = salesUrlUtil.postCode();
            restTemplate.postForEntity(url, JSONObject.fromObject(map).toString(), String.class);
        } catch (Exception ex) {
            log.error(" Invitation code initialization failed msg:{}", ex);
        }

    }


    @Override
    public void checkCode(String code) throws IOException {
        //校验验证码
        String url = salesUrlUtil.getCheckUrl();
        Map<String, Object> map = new HashMap<>();
        map.put("referralCode", code);
        url = OkHttpUtils.getUrl(url, map);
        OkHttpUtils.doGet(url);
    }

    /**
     * 修改店铺简介
     *
     * @param storeReq
     */
    @Override
    @Transactional
    public void updateStore(StoreReq storeReq) {
        Store store = storeDao.findOne(storeReq.getStoreId());
        store.setStoreLogo(storeReq.getLogo());
        store.setSummary(storeReq.getDetail());
        storeDao.save(store);
    }

    public void reduceCode(String code) throws IOException {
        //校验验证码
        String url = salesUrlUtil.getReduceCodeUrl();
        //校验验证码
        Map<String, Object> map = new HashMap<>();
        map.put("refCode", code);
        url = OkHttpUtils.getUrl(url, map);
        OkHttpUtils.doGet(url);
    }

    @Override
    @Transactional
    public void updatePaymentCfg(String storeId, String mchId, String key) throws StoreProfileNotExistException {
        StoreProfile profile = storeProfileDao.findByStoreId(storeId);
        if (null == profile) {
            throw new StoreProfileNotExistException();
        }

        profile.setStatus(StoreProfileStatus.APPROVED);


        Store store = storeDao.findOne(storeId);

        store.setMchId(mchId);
        store.setKey(key);


    }

    @Override
    public List<com.jy.api.vo.member.StoreVo> getMemberStoreLike(String memberId, String q) {
        List<Object[]> objects = storeDao.queryLikeStoreName(memberId, q);
        List<com.jy.api.vo.member.StoreVo> storeVos = objects.stream().map(e ->
                new com.jy.api.vo.member.StoreVo(e[0].toString(), e[1].toString(), e[2].toString())
        ).collect(Collectors.toList());
        return storeVos;
    }

    @Override
    public List<com.jy.api.vo.member.StoreVo> getMemberAllStoreLike(String q) {
        List<Store> objects = storeDao.queryLikeStoreNameAll(q);
        List<com.jy.api.vo.member.StoreVo> storeVos = objects.stream().map(e ->
                new com.jy.api.vo.member.StoreVo(e.getId(), e.getName(), e.getAddr())
        ).collect(Collectors.toList());
        return storeVos;
    }

    @Override
    public List<StoreMemberInfoVo> getStoreIndo(String memberId, Pageable pageable) {
        List<StoreMemberInfoVo> storeMemberInfoVos = new ArrayList<>();
        List<Map<String, Object>> maps = memberAccountDao.queryStoreInfo(memberId, pageable);

        List<String> storeIds = maps.stream().map(e -> e.get("storeId").toString()).collect(Collectors.toList());
        if (storeIds.size() > 0) {
            Map<String, Store> stores = storeDao.findByIdIn(storeIds).stream()
                    .collect(Collectors.toMap(Store::getId, store -> store));
            for (Map<String, Object> map : maps) {
                Store store = stores.get(map.get("storeId").toString());
                StoreMemberInfoVo storeMemberInfoVo = new StoreMemberInfoVo(store.getId(), store.getName(),
                        store.getAddr(), Double.parseDouble(map.get("amount").toString()), Integer.parseInt(map.get("points").toString()));
                storeMemberInfoVos.add(storeMemberInfoVo);
            }
        }

        return storeMemberInfoVos;
    }

    @Override
    public String creatClient(String storeId) {

        //文件夹路径
        //配置文件路径
        String fileKey = "client/" + storeId + "/config.ini";
        try {
            //生成配置参数并且上传到OSS
            ImageFileOssUtil.imageUpload(new ByteArrayInputStream(StoreConfigUtil.CLIENT_CONFIG.replace("STORE_ID", storeId).getBytes()), fileKey);
            fileKey = ImageFileOssUtil.getUrl(fileKey);
        } catch (FileNotFoundException e) {
            log.error("文件未找到", e);
        }
        return fileKey;
    }

    @Override
    public String creatClientBat(String storeId) {
        //文件夹路径
        //配置文件路径
        String fileKey = "client/" + storeId + "/ie.bat";
        try {
            //生成配置参数
            ImageFileOssUtil.imageUpload(new ByteArrayInputStream(StoreConfigUtil.CLIENT_BAT_CONFIG.replace("STORE_ID", storeId).getBytes()), fileKey);
            fileKey = ImageFileOssUtil.getUrl(fileKey);
        } catch (FileNotFoundException e) {
            log.error("文件未找到", e);
        }
        return fileKey;
    }

    //
    @Async
    public String getUrl(String storeId) {
        String fileKey = "client/" + storeId + ".zip";

        try {
            ImageFileOssUtil.downloadAndUpload(storeId);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String url = ImageFileOssUtil.getUrl(fileKey);
        return url;


    }

    @Async
    public String getNewUrl(String storeId) {
        String targetFileName = "newPlat/" + storeId + ".zip";
        try {
            ImageFileOssUtil.newDown(storeId, "huoxingy.zip", targetFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String url = ImageFileOssUtil.getUrl(targetFileName);
        return url;


    }


    /**
     * 查找呼叫首页信息
     *
     * @param storeId
     * @return
     */
    @Override
    public MarsCallRes findMarsCallIndex(String storeId) {
        Store store = storeDao.findOne(storeId);
        if (store == null) {
            return new MarsCallRes();
        }
        Date begin = MyDateUtils.getMinMonthDate();
        Date end = MyDateUtils.getMaxMonthDate();

        if (store.isCall() && new Date().getTime() - store.getCallEndTime().getTime() < 0) {
            List<Employee> list = employeeDao.getEmp(storeId);
            List<Employee> employees = employeeDao.findListByStoreIdAndEnabledOrderByWorkDesc(storeId, true);

            List<Object[]> reward = rewardDao.findIndexSumRewardAndOrderByAmountAsc(storeId, begin, end);

            List<MarsCallRes.RewardRank> rewardRanks = new ArrayList<>();

            List<Object[]> callCount = callServiceDao.countByStoreIdAndTime(storeId, begin, end);
            Map map = new HashMap();
            for (Object[] objects : callCount) {
                map.put(objects[0].toString(), objects[1]);
            }
            List<MarsCallRes.Emp> emps = new ArrayList<>();
            MarsCallRes marsCallRes = new MarsCallRes();
            marsCallRes.setNotice(store.getNotice());
            marsCallRes.setNetTitle(store.getNetTitle());
            marsCallRes.setTitle(store.getTitle());
            marsCallRes.setSummary(store.getSummary());
            marsCallRes.setLogo(store.getStoreLogo());
            marsCallRes.setStoreName(store.getName());
            marsCallRes.setQrCode(store.getQRCode());
            int count = 0;
            //打赏金额排行榜
            for (Object[] objects : reward) {
                MarsCallRes.RewardRank rewardRank = new MarsCallRes.RewardRank();
                rewardRank.setAmount(Double.valueOf(objects[2].toString()));
                rewardRank.setMemberName(objects[0].toString());
                rewardRank.setCount(Integer.valueOf(objects[1].toString()));
                rewardRanks.add(rewardRank);
            }
            marsCallRes.setRewardRanks(rewardRanks);
            //员工服务评价榜
            List<MarsCallRes.EmpRank> empRanks = new ArrayList<>();
            for (Employee employee : list) {
                if (employee.getGroup().isShow()) {
                    MarsCallRes.EmpRank empRank = new MarsCallRes.EmpRank();
                    if (null != map.get(employee.getId())) {
                        empRank.setCount(Integer.parseInt(map.get(employee.getId()).toString()));
                    } else {
                        empRank.setCount(0);
                    }
                    empRank.setName(employee.getName());
                    empRank.setEmpId(employee.getId());
                    empRank.setAppraise(employee.getAvgServiceMark());
                    empRanks.add(empRank);
                }

            }
            Random ne = new Random();//实例化一个random的对象ne
            for (Employee employee : employees) {
                if (employee.getGroup().isShow()) {
                    if (!employee.getGroup().getId().equals("1")) {
                        MarsCallRes.Emp marsEmp = new MarsCallRes.Emp();
                        //员工评价榜
                        Integer code = ne.nextInt(9999 - 1000 + 1) + 1000;//为变量赋随机值1000-9999
                        marsEmp.setEmpId(employee.getId());
                        marsEmp.setEmpName(employee.getName());
                        marsEmp.setEmpPhoto(employee.getPhoto());
                        if (!employee.getGroup().isReward() || !employee.isWork()) {
                            marsEmp.setRandom(0);
                        } else {
                            marsEmp.setRandom(code);
                        }
                        marsEmp.setEmpJob(employee.getGroup().getName());
                        marsEmp.setWork(employee.isWork());
                        marsEmp.setReward(employee.getGroup().isReward());
                        count = count + 1;
                        emps.add(marsEmp);
                    } else {
                        continue;
                    }
                } else {
                    continue;
                }
            }
            marsCallRes.setEmpRanks(empRanks);
            marsCallRes.setReward(store.isReward());
            marsCallRes.setEmpCount(count);
            marsCallRes.setEmps(emps);
            return marsCallRes;
        } else {
            MarsCallRes res = new MarsCallRes();
            res.setEmps(new ArrayList<>());
            return res;
        }
    }

    @Override
    public Map<String, Object> updateStoreByStoreId(UpdateStoreReq req) {
        Store store = storeDao.findOne(req.getStoreId());
        Map<String, Object> map = new HashMap<>();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        Date endTime = null;
        try {
            if (null != req.getCallEndTime()) {
                endTime = simpleDateFormat.parse(req.getCallEndTime());
            }
        } catch (ParseException e) {
            log.info("时间转换异常");
            e.printStackTrace();
        }
        if (null == store.getCallTime()) {
            store.setCallTime(new Date());
        }
        store.setCall(req.isCall());
        if (null == store.getCallEndTime()) {
            if (store.isCall()) {
                try {
                    //   ImageFileOssUtil.downloadCallAndClientUpload(req.getStoreId());
                    ImageFileOssUtil.downloadCallAndServiceUpload(req.getStoreId());
                    //ImageFileOssUtil.downloadXpCallAndClientUpload(req.getStoreId());
                } catch (IOException e) {
                    log.info("呼叫客户端/服务端生成异常");
                    e.printStackTrace();
                }
            }
        }
        if (!req.isCall()) {
            store.setCallEndTime(null);
        } else {
            store.setCallEndTime(endTime);
        }
        storeDao.save(store);
        map.put("result", new Result(200, "修改成功"));
        return map;
    }

    @Override
    @Transactional
    public Result updateStoreByZero(UpdateRewardReq req) {
        Store store = storeDao.findOne(req.getStoreId());
        store.setZero(req.isZero());
        storeDao.save(store);
        return new Result(200, "修改成功");
    }

    @Override
    @Transactional
    public Result updateStoreByDiscount(UpdateRewardReq req) {
        Store store = storeDao.findOne(req.getStoreId());
        store.setDiscount(req.isDiscount());
        storeDao.save(store);
        return new Result(200, "修改成功");
    }

    @Override
    @Transactional
    public Map<String, Object> updateReward(UpdateRewardReq req) {
        Store store = storeDao.findOne(req.getStoreId());
        Map<String, Object> map = new HashMap<>();
        store.setReward(req.isReward());
        storeDao.save(store);
        map.put("result", new Result(200, "保存成功"));
        return map;
    }

    @Override
    public List<Store> likeStoreName(String name) {
        return storeDao.findByStoreNameLike(name);
    }

    @Override
    @Transactional
    public Map<String, Object> setStoreSecond(SetStoreCallTime callTime) {
        Map<String, Object> map = new HashMap<>();
        Store store = storeDao.findOne(callTime.getStoreId());
        store.setCallSecond(callTime.getSecond());
        Store returnStore = storeDao.save(store);
        map.put("result", new Result(200, "呼叫时间设置成功"));
        map.put("data", returnStore);
        return map;
    }

    @Override
    @Transactional
    public Map<String, Object> updateStoreById(StoreUpdateReq req) {
        Map<String, Object> map = new HashMap<>();
        StoreType storeType = storeTypeDao.findOne(req.getTypeId());

        Store store = storeDao.findOne(req.getStoreId());
        store.setName(req.getName());
        store.setAddr(req.getAddr());
        store.setTypeName(storeType.getName());
        store.setTypeCode(storeType.getCode());
        List<StorePay> storePay = storePayDao.findByStoreId(req.getStoreId());
        for (StorePay pay : storePay) {
            pay.setStoreName(req.getName());
            storePayDao.save(pay);
        }
        Store returnStore = storeDao.save(store);
        map.put("result", new Result(200, "保存成功"));
        map.put("data", returnStore);
        return map;
    }

    @Override
    public List<Store> findByStoreNameLike(String name) {
        return storeDao.findByStoreNameLike(name);


    }

    @Override
    public Result setPsw(SetPswReq req) {
        Store store = storeDao.findOne(req.getStoreId());
        store.setPsw(req.getPsw());
        storeDao.save(store);
        return new Result(200, "修改成功");
    }

    @Override
    public Result judgePsw(SetPswReq req) {
        Store store = storeDao.findOne(req.getStoreId());
        if (StringUtils.contains(req.getJudgePsw(), store.getPsw())) {
            return new Result(200, "密码正确");
        } else {
            return new Result(400, "密码错误");
        }
    }

    @Override
    public Result getProductDay(String type, String storeId) {
        Date earliest = new Date();
        Date lastest = new Date();
        int days = 0;
        switch (type) {
            case "DAY":
                Date day = MyDateUtils.increaseDate(new Date(), -1);
                earliest = MyDateUtils.getEarliest(day);
                lastest = MyDateUtils.getLastest(day);
                break;
            case "SEVEN":
                Date sevenBegin = MyDateUtils.increaseDate(new Date(), -7);
                Date sevenEnd = MyDateUtils.increaseDate(new Date(), -1);
                earliest = MyDateUtils.getEarliest(sevenBegin);
                lastest = MyDateUtils.getLastest(sevenEnd);
                days = -7;
                break;
            case "FIFTEEN":
                Date fifteenBegin = MyDateUtils.increaseDate(new Date(), -15);
                Date fifteenEnd = MyDateUtils.increaseDate(new Date(), -1);
                earliest = MyDateUtils.getEarliest(fifteenBegin);
                lastest = MyDateUtils.getLastest(fifteenEnd);
                days = -15;
                break;
            case "THIRTY":
                Date thirtyBegin = MyDateUtils.increaseDate(new Date(), -30);
                Date thirtyEnd = MyDateUtils.increaseDate(new Date(), -1);
                earliest = MyDateUtils.getEarliest(thirtyBegin);
                lastest = MyDateUtils.getLastest(thirtyEnd);
                days = -30;
        }
        //查询同步之后的分类
        List<ProductTypeDayCount> productTypeDayCount = countDao.findByStoreIdAndDateBetweenOrderByDateAsc(storeId, earliest, lastest);
        List<ProductDatRes> res = new ArrayList<>();
        int i;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        //map放的是分类数据
        Map<String, ProductType> map = new HashMap<>();
        //查询正常分类
        List<ProductType> productTypes = productTypeDao.findByStoreIdAndEnabled(storeId, true);
        //查询网费
        List<ProductType> netType = productTypeDao.findByStoreIdAndEnabled("1", true);
        for (ProductType productType : productTypes) {
            if (null == productType.getParent()) {
                map.put(productType.getName(), productType);
            } else {
                map.put(productType.getParent().getName(), productType.getParent());
            }
        }
        map.put(netType.get(0).getName(), netType.get(0));
        for (i = days; i < 0; i++) {
            ProductDatRes productDatRes = new ProductDatRes();
            List<ProductDatRes.ProductData> productData = new ArrayList<>();
            Date thirtyBegin = MyDateUtils.increaseDate(new Date(), i);
            String format = sdf.format(thirtyBegin);
            String judge = format.toString().split(" ")[0];
            for (ProductTypeDayCount p : productTypeDayCount) {
                if (p.getDate().toString().startsWith(judge)) {
                    ProductDatRes.ProductData data = new ProductDatRes.ProductData();
                    BeanUtils.copyProperties(p, data);
                    productData.add(data);
                }
            }
            productDatRes.setList(productData);
            productDatRes.setDate(judge);
            res.add(productDatRes);
        }
        for (ProductDatRes pr : res) {
            List<ProductDatRes.ProductData> productData = new ArrayList<>();
            if (pr.getList().size() == 0) {
                map.forEach((k, v) -> {
                    ProductDatRes.ProductData getData = new ProductDatRes.ProductData(k, v.getStoreId(), pr.getDate());
                    productData.add(getData);
                    pr.setList(productData);
                });
            } else {
                map.forEach((k, v) -> pr.getList().add(new ProductDatRes.ProductData(v.getName(), storeId, pr.getDate())));
                for (ProductDatRes.ProductData data : pr.getList()) {
                    if (map.containsKey(data.getTypeName())) {
                        data.setAmount(data.getAmount());
                        data.setQty(data.getQty());
                    }
                }
                log.info("首页店铺id{},日期{},最终数据{}", storeId, pr.getDate(), pr.getList());
                ArrayList<ProductDatRes.ProductData> collect = pr.getList().stream().collect(
                        collectingAndThen(
                                toCollection(() -> new TreeSet<>(Comparator.comparing(ProductDatRes.ProductData::getTypeName))), ArrayList::new)
                );
                pr.getList().removeAll(pr.getList());
                pr.setList(collect);
            }
        }
        return new Result(200, "数据获取成功", res);
    }


    /**
     * @param data1
     * @param data2
     * @return data1 与 data2拼接的结果
     */
    public static byte[] addBytes(byte[] data1, byte[] data2) {
        byte[] data3 = new byte[data1.length + data2.length];
        System.arraycopy(data1, 0, data3, 0, data1.length);
        System.arraycopy(data2, 0, data3, data1.length, data2.length);
        return data3;

    }

}
